package proxyhandler

import (
	"gitee.com/captials-team/ubdframe/src/common"
	"gitee.com/captials-team/ubdframe/src/domain/configstc"
	"github.com/gin-gonic/gin"
	"net/http"
	"net/http/httputil"
	"net/url"
	"strings"
)

type ItfProxyMode interface {
	Match(req *http.Request) bool
	ServeHTTP(rw http.ResponseWriter, req *http.Request)
}

// ProxyByPrefix 根据前缀转发的代理
type ProxyByPrefix struct {
	rule  *configstc.ProxyRule
	proxy *httputil.ReverseProxy
}

func NewProxyByPrefix(rule configstc.ProxyRule) *ProxyByPrefix {
	parseRootUrl, err := url.Parse(rule.Forward)
	common.ErrPanic(err)
	proxy := httputil.NewSingleHostReverseProxy(parseRootUrl)

	return &ProxyByPrefix{
		rule:  &rule,
		proxy: proxy,
	}
}

func (p *ProxyByPrefix) Match(req *http.Request) bool {
	if strings.HasPrefix(req.URL.Path, p.rule.Match) {
		return true
	}
	return false
}

func (p *ProxyByPrefix) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
	req.URL.Path = strings.Replace(req.URL.Path, p.rule.Match, p.rule.Replace, 1)
	p.proxy.ServeHTTP(rw, req)
}

// ProxyByFixed 固定匹配转发
type ProxyByFixed struct {
	rule  *configstc.ProxyRule
	proxy *httputil.ReverseProxy
}

func NewProxyByFixed(rule configstc.ProxyRule) *ProxyByFixed {
	parseRootUrl, err := url.Parse(rule.Forward)
	common.ErrPanic(err)
	proxy := httputil.NewSingleHostReverseProxy(parseRootUrl)

	return &ProxyByFixed{
		rule:  &rule,
		proxy: proxy,
	}
}

func (p *ProxyByFixed) Match(req *http.Request) bool {
	return req.URL.Path == p.rule.Match
}

func (p *ProxyByFixed) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
	req.URL.Path = strings.Replace(req.URL.Path, p.rule.Match, p.rule.Replace, 1)
	p.proxy.ServeHTTP(rw, req)
}

// ProxyNone 空代理
type ProxyNone struct {
}

func (p *ProxyNone) Match(req *http.Request) bool {
	return false
}

func (p *ProxyNone) ServeHTTP(rw http.ResponseWriter, req *http.Request) {

}

func NewProxy(rule configstc.ProxyRule) ItfProxyMode {
	switch rule.Mode {
	case configstc.ProxyModePrefix:
		return NewProxyByPrefix(rule)
	case configstc.ProxyModeFix:
		return NewProxyByFixed(rule)
	}
	return &ProxyNone{}
}

func NewProxyGroup(rules ...configstc.ProxyRule) []ItfProxyMode {
	var arr []ItfProxyMode

	for _, v := range rules {
		arr = append(arr, NewProxy(v))
	}
	return arr
}

func ProxyHandler(rules ...ItfProxyMode) gin.HandlerFunc {
	return func(ctx *gin.Context) {
		for _, v := range rules {
			if v.Match(ctx.Request) {
				v.ServeHTTP(ctx.Writer, ctx.Request)
				ctx.Abort()
				break
			}
		}
	}
}
